package cloud.keveri.gateway.sdk;

import cloud.keveri.base.KeveriException;
import cloud.keveri.gateway.dto.ServiceDefinition;
import cloud.keveri.gateway.dto.ServiceInstance;
import cloud.keveri.registry.api.InstanceRegisterRepository;
import cloud.keveri.gateway.dto.KeveriClientConfigure;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.lang.NonNull;

import java.util.Map;
import java.util.Optional;
import java.util.Properties;

import static cloud.keveri.gateway.sdk.ClientSDKErrorCodeConstants.REGISTRY_ARGUMENT_ERROR;
import static cloud.keveri.gateway.sdk.def.Const.APP_NAME;
import static cloud.keveri.gateway.sdk.def.Const.CONTEXT_PATH;

/**
 * <p>
 * 作者：沈自在
 **/
@Slf4j
public abstract class AbstractServiceDiscoverySupport<T>
        implements ApplicationListener<ContextRefreshedEvent> {

    /**
     *
     */
    protected final String contextPath;

    /**
     *
     */
    protected final String appName;

    /**
     *
     */
    private ApplicationContext context;

    /**
     *
     */
    @Getter
    private final InstanceRegisterRepository register;

    @Override
    public void onApplicationEvent(@NonNull ContextRefreshedEvent event) {
        // 1. 提取容器
        context = event.getApplicationContext();

        // 2. 提取 App Bean
        Map<String, T> beans = acquireTargetBean(context);
        if (CollUtil.isEmpty(beans)) {
            return;
        }

        // 3. 提取方法
        for (T service : beans.values()) {
            processRegistry(context, service);
        }
    }

    protected abstract void processRegistry(ApplicationContext context, T service);


    public AbstractServiceDiscoverySupport(final KeveriClientConfigure configure, InstanceRegisterRepository register) {
        // 1. 提取参数
        Properties props = configure.getProps();
        this.appName = props.getProperty(APP_NAME);
        this.contextPath = "/" + Optional.ofNullable(props.getProperty(CONTEXT_PATH));

        // 2. 严谨检测
        if (StrUtil.isAllNotBlank(appName, contextPath)) {
            throw new KeveriException(REGISTRY_ARGUMENT_ERROR);
        }

        // 3. 初始化注册中心
        this.register = register;
        this.register.init(configure);
    }

    /**
     *
     */
    protected void register(ServiceDefinition serviceDefinition, ServiceInstance serviceInstance) {
        //直接调用注册中心的api
        register.register(serviceDefinition, serviceInstance);
    }

    /**
     *
     */
    protected abstract Map<String, T> acquireTargetBean(ApplicationContext context);
}
